package com.credithc.signature.manager.service;

import com.credithc.baseserv.core.codes.CoreCodes;
import com.credithc.baseserv.core.exception.BsException;
import com.credithc.baseserv.core.message.Message;
import com.credithc.signature.common.constant.ManagerConstant;
import com.credithc.signature.common.mapper.SealChannelMapper;
import com.credithc.signature.common.po.Channel;
import com.credithc.signature.common.ro.manager.ChannelRo;
import com.credithc.signature.common.ro.manager.RequestLogRo;
import com.credithc.signature.common.ro.manager.SealInfoRo;
import com.credithc.signature.common.ro.manager.TemplateRo;
import com.credithc.signature.common.service.ChannelService;
import com.credithc.signature.manager.client.AuthClient;
import com.credithc.signature.manager.client.SaasClient;
import com.credithc.signature.manager.ro.ProductRo;
import com.credithc.signature.manager.ro.TokenRo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 描 述: 授权服务类<br/>
 * 作 者: hujingbo<br/>
 * 创 建：2019年07⽉24⽇<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
@Service
@Slf4j
public class AuthorizationService {

    @Autowired
    AuthClient authClient;

    @Autowired
    SaasClient saasClient;

    @Autowired
    ChannelService channelService;

    @Autowired
    SealChannelMapper sealChannelMapper;


    /**
     * 获取模板的查询权限
     *
     * @param templateRo
     * @param token
     * @param request
     * @return
     */
    public TemplateRo authTemplate(TemplateRo templateRo, String token, HttpServletRequest request) throws BsException {
        TokenRo authData = getAuthData(token, request);
        if (authData != null) {
            String productCode = authData.getProductCode();
            log.info("获取模板的查询权限:productCode=" + productCode);
            Channel channel = channelService.selectChannelByCode(productCode);
            if (channel != null) {
                List<Integer> channelIds = new ArrayList<>();
                channelIds.add(channel.getId());
                String foreachParams = buildForeachParams(channelIds);
                templateRo.setChannelIds(foreachParams);
            }
        }
        return templateRo;
    }


    /**
     * 获取请求记录查询权限
     *
     * @param requestLogRo
     * @param token
     * @param request
     * @return
     */
    public RequestLogRo authRequestLog(RequestLogRo requestLogRo, String token, HttpServletRequest request) {
        TokenRo authData = getAuthData(token, request);
        if (authData != null) {
            String productCode = authData.getProductCode();
            log.info("获取请求记录的查询权限:productCode=" + productCode);
            List<String> channelNos = new ArrayList<>();
            channelNos.add(productCode);
            Channel channel = channelService.selectByChannelNo(productCode);
            if (StringUtils.isNotEmpty(channel.getChannelMappingNo())) {
                channelNos.add(channel.getChannelMappingNo());
            }
            requestLogRo.setChannelNos(channelNos);
        }
        return requestLogRo;
    }

    /**
     * 获取渠道查询权限
     *
     * @param channelRo
     * @param token
     * @param request
     * @return
     */
    public ChannelRo authChannelRo(ChannelRo channelRo, String token, HttpServletRequest request) {
        TokenRo authData = getAuthData(token, request);
        if (authData != null) {
            //判断时否时租户管理员 是：查询所有 否：根据渠道ID查询
            String productCode = authData.getProductCode();
            log.info("获取渠道的查询权限:productCode=" + productCode);
            List<String> channelNos = new ArrayList<>();
            channelNos.add(productCode);
            channelRo.setChannelNos(channelNos);
        }
        return channelRo;
    }

    /**
     * 获取公章信息查询权限
     *
     * @param sealInfoRo
     * @param token
     * @param request
     * @return
     */
    public SealInfoRo authSealInfoRo(SealInfoRo sealInfoRo, String token, HttpServletRequest request) {
        TokenRo authData = getAuthData(token, request);
        if (authData != null) {
            String productCode = authData.getProductCode();
            log.info("获取印章的查询权限:productCode=" + productCode);
            sealInfoRo.setChannelNo(productCode);
        }
        return sealInfoRo;
    }

    /**
     * 获取当前用户的渠道ID
     *
     * @param token
     * @param request
     * @return
     */
    public List<String> authChannelNo(String token, HttpServletRequest request) {
        TokenRo authData = getAuthData(token, request);
        List<String> channelNos = new ArrayList<>();
        if (authData != null) {
            String productCode = authData.getProductCode();
            channelNos.add(productCode);
        }
        return channelNos;
    }

    /**
     * 根据token和request查询数据权限
     *
     * @param token
     * @param request
     * @return
     */
    public TokenRo getAuthData(String token, HttpServletRequest request) {
        if (StringUtils.isNotBlank(token) && !ManagerConstant.LOCAL_ADDR.equals(request.getRemoteAddr())) {
            log.info("开始查询数据权限......");
            Message<TokenRo> userByToken = authClient.getUserInfoByToken(token);
            log.info("数据权限查询结果:" + userByToken.toString());
            if (CoreCodes.CORE_SUCCESS == userByToken.getCode()) {
                TokenRo authData = userByToken.getData();
                if (ManagerConstant.NOT_TENANT.equals(authData.getCompanyId())) {
                    log.error("当前登录用户不是租户......");
                    throw new BsException(CoreCodes.CORE_SYS_ERROR, "当前登录用户不是租户......");
                } else {
                    return authData;
                }
            }
            log.info("结束查询数据权限......");
        }
        return null;
    }

    /**
     * 给运营平台使用
     *
     * @param token
     * @param request
     * @return
     */
    public TokenRo getOperateAuthData(String token, HttpServletRequest request) {
        if (StringUtils.isNotBlank(token) && !ManagerConstant.LOCAL_ADDR.equals(request.getRemoteAddr())) {
            log.info("开始查询数据权限......");
            Message<TokenRo> userByToken = authClient.getUserInfoByToken(token);
            log.info("数据权限查询结果:" + userByToken.toString());
            if (CoreCodes.CORE_SUCCESS == userByToken.getCode()) {
                TokenRo authData = userByToken.getData();
                return userByToken.getData();
            }
            log.info("结束查询数据权限......");
        }
        return null;
    }

    /**
     * 根据companyID获取渠道ID集合
     *
     * @param authData
     * @return
     */
    private List<Integer> getChannelIds(TokenRo authData) {
        List<String> channelCodes = getChannelCodes(authData);
        List<Integer> channelIds = new ArrayList<>(10);
        for (String channelCode : channelCodes) {
            Channel channel = channelService.selectChannelByCode(channelCode);
            if (channel != null) {
                channelIds.add(channel.getId());
            }
        }
        return channelIds;
    }

    /**
     * 获取渠道编码
     *
     * @param authData
     * @return
     */
    public List<String> getChannelCodes(TokenRo authData) {
        List<Integer> companyIds = new ArrayList<>(10);
        companyIds.add(authData.getCompanyId());
        Message<List<ProductRo>> productList = saasClient.getProductList(companyIds);
        List<ProductRo> data = productList.getData();
        log.info("获取租户管理员产品列表：" + Arrays.toString(data.stream().map(ProductRo::getCode).toArray()));
        return data.stream().map(ProductRo::getCode).collect(Collectors.toList());
    }

    /**
     * 封装foreach参数
     *
     * @param params
     * @return
     */
    private String buildForeachParams(List<Integer> params) {
        StringBuffer bf = new StringBuffer();
        if (params != null) {
            params.forEach(p -> {
                bf.append(p);
                bf.append(",");
            });
            if (bf.length() > 0) {
                bf.deleteCharAt(bf.toString().length() - 1);
            }
        }
        return bf.toString();
    }

}
